package com.xiaoyu.tio.redis;

import java.io.Closeable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tio.client.ClientChannelContext;
import org.tio.client.ClientGroupContext;
import org.tio.client.ReconnConf;
import org.tio.client.TioClient;
import org.tio.core.Node;
import org.tio.core.Tio;

import com.xiaoyu.tio.redis.handler.RedisHandler;

public class TedisClient implements Closeable{
	
	private final static Logger logger = LoggerFactory.getLogger(TedisClient.class);
	
	private RedisConfig redisconfig = new RedisConfig();
	
	private ClientChannelContext clientChannelContext;
	
	private RedisHandler redisHandler;
	
	private static TedisClient client = new TedisClient();
	
	private TioClient aioClient;
	
	private TedisClient() {
	
	}
	
	public TedisClient connect() throws Exception {
		if(clientChannelContext != null) {
			logger.error("请勿重复调用connect方法！！");
			return this;
		}
		Node serverNode = new Node(redisconfig.host, redisconfig.port);
		redisHandler = new RedisHandler();
		ReconnConf reconnConf = new ReconnConf();
		ClientGroupContext groupContext = new ClientGroupContext(redisHandler, null, reconnConf);
		aioClient = new TioClient(groupContext);
		clientChannelContext = aioClient.connect(serverNode);
		if(redisconfig.password != null && !redisconfig.password.equals("")) {
			MessageResponse response = sendCommand(RedisCmd.AUTH.name(), redisconfig.password);
			if(!response.getData().get(0).equals(true)) {
				throw new IllegalArgumentException("redis 密碼錯誤！！");
			}
		}
		logger.debug("Tedis连接成功！！");
		return this;
	}
	
	public static RedisConfig create() {	
		return client.redisconfig;
	}

	public MessageResponse sendCommand(RedisCmd cmd, String... parms) throws TimeoutException {
		return this.sendCommand(cmd.name(), parms);
	}
	
	public MessageResponse sendCommand(String cmd, String... parms) throws TimeoutException {
		if(clientChannelContext == null) {
			logger.error("请先调用connect方法！！");
			throw new IllegalArgumentException("请先调用connect方法！！");
		}
		RedisPacket packet = new RedisPacket();
		List<String> arrayParms = new ArrayList<>();
		packet.setCmd(cmd);
		for (String o : parms) {
			arrayParms.add(o);
		}
		packet.setParms(arrayParms);
		CompletableFuture<MessageResponse> future = new CompletableFuture<>();
		Tio.send(clientChannelContext, packet);
		Long id = packet.getId();
		redisHandler.stackAdd(id);
		redisHandler.addMessage(id, future);
		MessageResponse response = null;
		try {
			response = future.get(1, TimeUnit.SECONDS);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		} catch (TimeoutException e) {
			throw e;
		}
		return response;	
	}
	
	static class RedisConfig {
		
		private String host = "127.0.0.1";
		
		private Integer port = 6379;
		
		private String password;
		
        private int database = 0;

		public RedisConfig database(int database) {
			this.setDatabase(database);
			return this;
		}
		
		public RedisConfig port(Integer port) {
			this.port = port;
			return this;
		}
		
		public RedisConfig password(String password) {
			this.password = password;
			return this;
		}
		
		public RedisConfig host(String host) {
			this.host = host;
			return this;
		}

		public String getHost() {
			return host;
		}

		public void setHost(String host) {
			this.host = host;
		}

		public Integer getPort() {
			return port;
		}

		public void setPort(Integer port) {
			this.port = port;
		}

		public String getPassword() {
			return password;
		}

		public void setPassword(String password) {
			this.password = password;
		}


		public int getDatabase() {
			return database;
		}

		public void setDatabase(int database) {
			this.database = database;
		}
		
		public TedisClient bulid() {
			return client;
		}
		
		
		
	}

	@Override
	public void close() {	
		MessageResponse response;
		try {
			response = sendCommand(RedisCmd.QUIT.name());
			if(response.getData().get(0).equals(true)) {
				logger.info("已经成功退出redis！！");
			}
		} catch (TimeoutException e) {
			logger.error("主动退出redis失败！！");
		}		
		Tio.close(clientChannelContext, "主动关闭");
	}
}
